package cn.admin.configcenter.configservice.persist;

import cn.admin.configcenter.configservice.domain.ConfigInfo;
import cn.admin.configcenter.configservice.domain.Page;
import cn.admin.configcenter.configservice.domain.PaginationHelper;
import cn.admin.configcenter.configservice.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

@Repository("derbyAdvancedRepository")
public class ConfigAdvancedDAODerbyImpl implements ConfigAdvancedDAO {
    private static final Logger LOG = LoggerFactory.getLogger(ConfigAdvancedDAODerbyImpl.class);

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private static final BaseConfigInfoRowMapper BASE_CONFIG_INFO_ROW_MAPPER =
            new BaseConfigInfoRowMapper();

    @Override
    public Page<ConfigInfo> findConfigInfoByDataIdAndGroup(int pageNo, int pageSize, String group, String dataId) {
        PaginationHelper<ConfigInfo> helper = new PaginationHelper<>();

        try {
            return helper.fetchPage(this.jdbcTemplate,
                    "select count(ID) from config_info where data_id like '%'||?||'%' and group_id like '%'||?||'%' ",
                    "select ID,data_id,src_ip,group_id,content,app_name from config_info where data_id like '%'||?||'%' and group_id like '%'||?||'%' order by gmt_create desc ",
                    new Object[]{dataId, group}, pageNo, pageSize, BASE_CONFIG_INFO_ROW_MAPPER);
        } catch (CannotGetJdbcConnectionException e) {
            LOG.error("[db-error] " + e.toString(), e);
            throw e;
        }
    }

    @Override
    public Page<ConfigInfo> findConfigInfoByDataId(int pageNo, int pageSize, String dataId) {
        PaginationHelper<ConfigInfo> helper = new PaginationHelper<>();

        try {
            return helper.fetchPage(this.jdbcTemplate,
                    "select count(ID) from config_info where data_id like '%'||?||'%'",
                    "select ID,data_id,src_ip,group_id,content,app_name from config_info where data_id like '%'||?||'%' order by gmt_create desc ",
                    new Object[]{dataId}, pageNo, pageSize, BASE_CONFIG_INFO_ROW_MAPPER);
        } catch (CannotGetJdbcConnectionException e) {
            LOG.error("[db-error] " + e.toString(), e);
            throw e;
        }
    }

    @Override
    public Page<ConfigInfo> findConfigInfoByGroup(int pageNo, int pageSize, String group) {
        PaginationHelper<ConfigInfo> helper = new PaginationHelper<>();

        try {
            return helper.fetchPage(this.jdbcTemplate,
                    "select count(ID) from config_info where group_id like '%'||?||'%' ",
                    "select ID,data_id,group_id,src_ip, content,app_name from config_info where group_id like '%'||?||'%' order by gmt_create desc ",
                    new Object[]{group}, pageNo, pageSize, BASE_CONFIG_INFO_ROW_MAPPER);
        } catch (CannotGetJdbcConnectionException e) {
            LOG.error("[db-error] " + e.toString(), e);
            throw e;
        }
    }

    @Override
    public Page<ConfigInfo> findAllConfigInfo(int pageNo, int pageSize) {
        String select = "SELECT id,data_id,group_id,src_ip,content,app_name " +
                "FROM config_info order by gmt_create desc OFFSET ? ROWS FETCH NEXT ? ROWS ONLY ";
        int totalCount = this.totalConfigCount();
        int pageCount = totalCount / pageSize;
        if (totalCount > pageSize * pageCount) {
            ++pageCount;
        }

        if (pageNo > pageCount) {
            return null;
        } else {
            Page<ConfigInfo> page = new Page<>();
            page.setCurrentPage(pageNo);
            page.setTotalSize(totalCount);

            try {
                int offsetRows = (pageNo - 1) * pageSize;
                List<ConfigInfo> resultConfigList = this.jdbcTemplate.query(select,
                        new Object[]{offsetRows, pageSize}, BASE_CONFIG_INFO_ROW_MAPPER);
                page.setResult(resultConfigList);
                return page;
            } catch (EmptyResultDataAccessException e) {
                return page;
            } catch (CannotGetJdbcConnectionException e) {
                LOG.error("[db-error] " + e.toString(), e);
                throw e;
            }
        }
    }

    @Override
    public Page<ConfigInfo> findConfigInfoLike(int pageNo, int pageSize, String dataId, String group, String content, String srcIp) {
        if (StringUtils.isBlank(dataId) && StringUtils.isBlank(group) && StringUtils.isBlank(srcIp)) {
            return new Page<>();
        } else {
            PaginationHelper<ConfigInfo> helper = new PaginationHelper<>();
            String sqlCountRows = "select count(ID) from config_info where ";
            String sqlFetchRows = "select ID,data_id,group_id,src_ip,content,app_name from config_info where ";
            String where = " 1=1 ";
            String order = " order by gmt_create desc ";
            List<String> params = new ArrayList<>();
            if (!StringUtils.isBlank(dataId)) {
                where = where + " and data_id like ? ";
                params.add(this.generateLikeArgument(dataId));
            }

            if (!StringUtils.isBlank(group)) {
                where = where + " and group_id like ? ";
                params.add(this.generateLikeArgument(group));
            }

            if (!StringUtils.isBlank(content)) {
                where = where + " and content like ? ";
                params.add(this.generateLikeArgument(content));
            }

            if (!StringUtils.isBlank(srcIp)) {
                where = where + " and src_ip like ? ";
                params.add(this.generateLikeArgument(srcIp));
            }

            try {
                return helper.fetchPage(this.jdbcTemplate, sqlCountRows + where,
                        sqlFetchRows + where + order,
                        params.toArray(), pageNo, pageSize, BASE_CONFIG_INFO_ROW_MAPPER);
            } catch (CannotGetJdbcConnectionException e) {
                LOG.error("[db-error] " + e.toString(), e);
                throw e;
            }
        }
    }

    @Override
    public Page<ConfigInfo> findPublishedConfigInfoByIp(int pageNo,
                                                        int pageSize,
                                                        String clientIp) {
        if (StringUtils.isBlank(clientIp)) {
            return this.findAllConfigInfo(pageNo, pageSize);
        } else {
            PaginationHelper<ConfigInfo> helper = new PaginationHelper<>();
            String sqlCountRows = "select count(ID) from config_info where ";
            String sqlFetchRows = "select ID,data_id,group_id,src_ip,content,app_name from config_info where ";
            String where = " 1=1 ";
            List<String> params = new ArrayList<>();
            if (!StringUtils.isBlank(clientIp)) {
                where = where + " and src_ip like ? ";
                params.add(this.generateLikeArgument(clientIp));
            }

            try {
                return helper.fetchPage(this.jdbcTemplate, sqlCountRows + where,
                        sqlFetchRows + where, params.toArray(), pageNo, pageSize,
                        BASE_CONFIG_INFO_ROW_MAPPER);
            } catch (CannotGetJdbcConnectionException e) {
                LOG.error("[db-error] " + e.toString(), e);
                throw e;
            }
        }
    }

    public int totalConfigCount() {

        String sql = " SELECT COUNT(ID) FROM config_info";
        Integer i = this.jdbcTemplate.queryForObject(sql,null,
                Integer.class);
        return i == null ? 0 : i;

    }

    private String generateLikeArgument(String s) {

        return s.contains("*") ? s.replaceAll("\\*", "%") : s;

    }

    static final class BaseConfigInfoRowMapper implements RowMapper<ConfigInfo> {

        @Override
        public ConfigInfo mapRow(ResultSet rs, int i) throws SQLException {
            ConfigInfo config = new ConfigInfo();
            config.setId(rs.getLong("id"));
            config.setDataId(rs.getString("data_id"));
            config.setGroup(rs.getString("group_id"));
            config.setContent(rs.getString("content"));
            config.setSrcIp(rs.getString("src_ip"));
            config.setAppName(rs.getString("app_name"));
            return config;
        }
    }

}
